package com.example.service;

import com.example.dto.IdentityDTO;
import com.example.entity.IdentityDO;
import com.example.exception.BusinessException;
import com.example.mapper.IdentityMapper;
import com.example.service.impl.IdentityServiceImpl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

class IdentityServiceTest {

    @Mock
    private IdentityMapper identityMapper;

    @InjectMocks
    private IdentityServiceImpl identityService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testAddIdentity_Success() {
        IdentityDTO identityDTO = new IdentityDTO();
        identityDTO.setIdentityName("testIdentity");
        identityDTO.setDescription("testDescription");

        when(identityMapper.selectOne(any())).thenReturn(null);
        when(identityMapper.insert(any())).thenReturn(1);

        assertTrue(identityService.addIdentity(identityDTO));

        verify(identityMapper).selectOne(any());
        verify(identityMapper).insert(any());
    }

    @Test
    void testAddIdentity_Failure() {
        IdentityDTO identityDTO = new IdentityDTO();
        identityDTO.setIdentityName("testIdentity");
        identityDTO.setDescription("testDescription");

        IdentityDO existingIdentity = new IdentityDO();
        existingIdentity.setIdentityId(1);
        existingIdentity.setIdentityName("testIdentity");
        existingIdentity.setCreateTime(new Date());
        existingIdentity.setUpdateTime(new Date());

        when(identityMapper.selectOne(any())).thenReturn(existingIdentity);

        assertThrows(BusinessException.class, () -> identityService.addIdentity(identityDTO));

        verify(identityMapper).selectOne(any());
        verify(identityMapper, never()).insert(any());
    }

    @Test
    void testDeleteIdentity_Success() {
        Integer identityId = 1;
        IdentityDO identityDO = new IdentityDO();
        identityDO.setIdentityId(identityId);
        identityDO.setIdentityName("testIdentity");
        identityDO.setCreateTime(new Date());
        identityDO.setUpdateTime(new Date());

        when(identityMapper.selectById(identityId)).thenReturn(identityDO);
        when(identityMapper.deleteById(identityId)).thenReturn(1);

        assertTrue(identityService.deleteIdentity(identityId));

        verify(identityMapper).selectById(identityId);
        verify(identityMapper).deleteById(identityId);
    }

    @Test
    void testDeleteIdentity_Failure() {
        Integer identityId = 1;

        when(identityMapper.selectById(identityId)).thenReturn(null);

        assertThrows(BusinessException.class, () -> identityService.deleteIdentity(identityId));

        verify(identityMapper).selectById(identityId);
        verify(identityMapper, never()).deleteById(identityId);
    }

    @Test
    void testEditIdentity_Success() {
        IdentityDTO identityDTO = new IdentityDTO();
        identityDTO.setIdentityId(1);
        identityDTO.setIdentityName("newIdentityName");
        identityDTO.setDescription("newDescription");

        IdentityDO existingIdentity = new IdentityDO();
        existingIdentity.setIdentityId(1);
        existingIdentity.setIdentityName("oldIdentityName");
        existingIdentity.setCreateTime(new Date());
        existingIdentity.setUpdateTime(new Date());

        when(identityMapper.selectById(identityDTO.getIdentityId())).thenReturn(existingIdentity);
        when(identityMapper.selectOne(any())).thenReturn(null);
        when(identityMapper.updateById(any())).thenReturn(1);

        assertTrue(identityService.editIdentity(identityDTO));

        verify(identityMapper).selectById(identityDTO.getIdentityId());
        verify(identityMapper).selectOne(any());
        verify(identityMapper).updateById(any());
    }

    @Test
    void testEditIdentity_Failure_NotFound() {
        IdentityDTO identityDTO = new IdentityDTO();
        identityDTO.setIdentityId(1);
        identityDTO.setIdentityName("newIdentityName");
        identityDTO.setDescription("newDescription");

        when(identityMapper.selectById(identityDTO.getIdentityId())).thenReturn(null);

        assertThrows(BusinessException.class, () -> identityService.editIdentity(identityDTO));

        verify(identityMapper).selectById(identityDTO.getIdentityId());
        verify(identityMapper, never()).selectOne(any());
        verify(identityMapper, never()).updateById(any());
    }

    @Test
    void testEditIdentity_Failure_DuplicateName() {
        IdentityDTO identityDTO = new IdentityDTO();
        identityDTO.setIdentityId(1);
        identityDTO.setIdentityName("newIdentityName");
        identityDTO.setDescription("newDescription");

        IdentityDO existingIdentity = new IdentityDO();
        existingIdentity.setIdentityId(1);
        existingIdentity.setIdentityName("oldIdentityName");
        existingIdentity.setCreateTime(new Date());
        existingIdentity.setUpdateTime(new Date());

        IdentityDO duplicateIdentity = new IdentityDO();
        duplicateIdentity.setIdentityId(2);
        duplicateIdentity.setIdentityName("newIdentityName");
        duplicateIdentity.setCreateTime(new Date());
        duplicateIdentity.setUpdateTime(new Date());

        when(identityMapper.selectById(identityDTO.getIdentityId())).thenReturn(existingIdentity);
        when(identityMapper.selectOne(any())).thenReturn(duplicateIdentity);

        assertThrows(BusinessException.class, () -> identityService.editIdentity(identityDTO));

        verify(identityMapper).selectById(identityDTO.getIdentityId());
        verify(identityMapper).selectOne(any());
        verify(identityMapper, never()).updateById(any());
    }

    @Test
    void testQueryIdentities() {
        String identityName = "testIdentity";
        List<IdentityDO> identities = new ArrayList<>();
        IdentityDO identityDO = new IdentityDO();
        identityDO.setIdentityId(1);
        identityDO.setIdentityName(identityName);
        identityDO.setCreateTime(new Date());
        identityDO.setUpdateTime(new Date());
        identities.add(identityDO);

        when(identityMapper.selectList(any())).thenReturn(identities);

        List<IdentityDO> queriedIdentities = identityService.queryIdentities(identityName);

        assertEquals(identities.size(), queriedIdentities.size());
        assertEquals(identityName, queriedIdentities.get(0).getIdentityName());

        verify(identityMapper).selectList(any());
    }
}